from datetime import datetime
from typing import Dict, List, Optional, Any
from bson import ObjectId  # pyright: ignore[reportMissingImports]


def calculate_task_progress(status: str, estimated_hours: Optional[float] = None, actual_hours: Optional[float] = None) -> int:
    """
    计算任务进度百分比（基于状态代码的通用判断）
    
    Args:
        status: 任务状态代码
        estimated_hours: 预估工时
        actual_hours: 实际工时
    
    Returns:
        进度百分比 (0-100)
    """
    if not status:
        return 0
    
    status_lower = status.lower()
    
    # 根据状态代码关键词判断（避免硬编码具体状态值）
    # 完成状态：包含 "done", "completed", "finished" 等关键词
    if any(keyword in status_lower for keyword in ["done", "completed", "finished"]):
        return 100
    
    # 进行中状态：包含 "in_progress", "processing", "doing" 等关键词
    if any(keyword in status_lower for keyword in ["in_progress", "processing", "doing"]):
        # 基于实际工时和预估工时计算进度
        if estimated_hours and actual_hours:
            return min(int((actual_hours / estimated_hours) * 100), 95)
        else:
            return 30  # 默认进行中进度
    
    # 评审状态：包含 "review" 等关键词
    if "review" in status_lower:
        return 90
    
    # 取消状态：包含 "cancelled", "cancel" 等关键词
    if any(keyword in status_lower for keyword in ["cancelled", "cancel"]):
        return 0
    
    # 默认返回0
    return 0


def calculate_requirement_progress(status: str) -> float:
    """
    计算需求进度百分比（基于状态代码的通用判断）
    
    Args:
        status: 需求状态代码
    
    Returns:
        进度百分比 (0.0-100.0)
    """
    if not status:
        return 0.0
    
    status_lower = status.lower()
    
    # 根据状态代码关键词判断（避免硬编码具体状态值）
    # 完成/实现状态：100%
    if any(keyword in status_lower for keyword in ["implemented", "done", "completed", "finished"]):
        return 100.0
    
    # 已批准状态：60%
    if any(keyword in status_lower for keyword in ["approved", "confirmed"]):
        return 60.0
    
    # 评审状态：30%
    if "review" in status_lower:
        return 30.0
    
    # 草稿/新建状态：10%
    if any(keyword in status_lower for keyword in ["draft", "new", "open"]):
        return 10.0
    
    # 取消状态：0%
    if any(keyword in status_lower for keyword in ["cancelled", "cancel"]):
        return 0.0
    
    # 默认返回0
    return 0.0


def is_task_overdue(due_date: Optional[datetime], status: str) -> bool:
    """
    判断任务是否逾期（基于状态代码的通用判断）
    
    Args:
        due_date: 截止日期
        status: 任务状态代码
    
    Returns:
        是否逾期
    """
    if not due_date:
        return False
    
    if not status:
        return datetime.utcnow() > due_date
    
    status_lower = status.lower()
    
    # 根据状态代码关键词判断（避免硬编码具体状态值）
    # 完成或取消状态不视为逾期
    if any(keyword in status_lower for keyword in ["done", "completed", "finished", "cancelled", "cancel", "closed"]):
        return False
    
    return datetime.utcnow() > due_date


def is_requirement_overdue(due_date: Optional[datetime], status: str) -> bool:
    """
    判断需求是否逾期（基于状态代码的通用判断）
    
    Args:
        due_date: 截止日期
        status: 需求状态代码
    
    Returns:
        是否逾期
    """
    if not due_date:
        return False
    
    if not status:
        return datetime.utcnow() > due_date
    
    status_lower = status.lower()
    
    # 根据状态代码关键词判断（避免硬编码具体状态值）
    # 完成或取消状态不视为逾期
    if any(keyword in status_lower for keyword in ["implemented", "done", "completed", "finished", "cancelled", "cancel", "closed"]):
        return False
    
    return datetime.utcnow() > due_date


def calculate_comment_count(comments: List[Dict]) -> int:
    """计算评论数量"""
    return len(comments or [])


def calculate_attachment_count(attachments: List[Dict]) -> int:
    """计算附件数量"""
    return len(attachments or [])


def calculate_total_time_spent(time_logs: List[Dict]) -> float:
    """计算总工时"""
    return sum(log.get("hours", 0) for log in (time_logs or []))


def format_task_response(
    task: Dict[str, Any],
    assignee_info: Optional[Dict] = None,
    reporter_info: Optional[Dict] = None,
    creator_info: Optional[Dict] = None,
    project_info: Optional[Dict] = None,
    version_info: Optional[Dict] = None,
    include_details: bool = False
) -> Dict[str, Any]:
    """
    格式化任务响应数据
    
    Args:
        task: 任务数据
        assignee_info: 指派人信息
        reporter_info: 报告人信息
        creator_info: 创建人信息
        project_info: 项目信息
        version_info: 版本信息（关联的版本，如果有多个则传入第一个）
        include_details: 是否包含详细信息（评论、附件、工时记录等）
    
    Returns:
        格式化后的任务数据
    """
    # 计算统计信息
    comment_count = calculate_comment_count(task.get("comments", []))
    attachment_count = calculate_attachment_count(task.get("attachments", []))
    total_time_spent = calculate_total_time_spent(task.get("time_logs", []))
    
    # 计算进度和逾期状态
    # 优先使用数据库中存储的 progress 字段，如果没有则计算
    stored_progress = task.get("progress")
    if stored_progress is not None:
        # 如果数据库中有存储的进度值，使用它
        progress = int(stored_progress) if isinstance(stored_progress, (int, float)) else 0
    else:
        # 如果没有存储的进度值，根据状态和工时计算
        progress = calculate_task_progress(
            task["status"],
            task.get("estimated_hours"),
            task.get("actual_hours")
        )
    is_overdue = is_task_overdue(task.get("due_date"), task["status"])
    
    # 基础响应数据
    response_data = {
        "id": str(task["_id"]),
        "title": task["title"],
        "description": task.get("description"),
        "task_type": task.get("type", task.get("task_type")),  # 兼容两种字段名
        "status": task["status"],
        "priority": task["priority"],
        "project_id": str(task["project_id"]) if task.get("project_id") else None,
        "project_name": project_info["name"] if project_info else None,
        "assignee_id": str(task["assignee_id"]) if task.get("assignee_id") else None,
        "assignee_name": assignee_info["name"] if assignee_info else None,
        "assignee_avatar": assignee_info.get("avatar") if assignee_info else None,
        "reporter_id": str(task["reporter_id"]) if task.get("reporter_id") else None,
        "reporter_name": reporter_info["name"] if reporter_info else None,
        "created_by": str(task["created_by"]),
        "creator_name": creator_info["name"] if creator_info else None,
        "creator_avatar": creator_info.get("avatar") if creator_info else None,  # 添加创建人头像
        "estimated_hours": task.get("estimated_hours"),
        "actual_hours": task.get("actual_hours"),
        "start_date": task.get("start_date"),
        "due_date": task.get("due_date"),
        "progress": progress,
        "is_overdue": is_overdue,
        "created_by": str(task["created_by"]),
        "created_at": task["created_at"],
        "updated_at": task["updated_at"],
        "comment_count": comment_count,
        "attachment_count": attachment_count,
        "total_time_spent": total_time_spent,
        "version_id": str(version_info["_id"]) if version_info is not None else None,
        "version_name": version_info.get("name") if version_info is not None else None,
        "version_number": version_info.get("version_number") if version_info is not None else None
    }
    
    # 如果需要详细信息，添加完整的评论、附件和工时记录
    if include_details:
        response_data.update({
            "tags": task.get("tags", []),
            "dependencies": [str(dep) for dep in task.get("dependencies", [])],
            "organization_id": str(task["organization_id"]) if task.get("organization_id") else None,
            "comments": [
                {
                    "id": str(comment.get("id", ObjectId())),
                    "content": comment["content"],
                    "author_id": str(comment.get("author_id", comment.get("user_id", ""))),
                    "user_id": str(comment.get("user_id", comment.get("author_id", ""))),
                    "created_at": comment["created_at"],
                    "updated_at": comment.get("updated_at")
                }
                for comment in task.get("comments", [])
            ],
            "attachments": [
                {
                    "id": str(attachment.get("id", ObjectId())),
                    "filename": attachment.get("filename", attachment.get("original_filename", "")),
                    "file_path": attachment.get("file_path") or attachment.get("url", ""),
                    "file_size": attachment.get("file_size", 0),
                    "content_type": attachment.get("content_type") or attachment.get("file_type", "application/octet-stream"),
                    "uploaded_by": str(attachment.get("uploaded_by", "")),
                    "uploaded_at": attachment.get("uploaded_at")
                }
                for attachment in task.get("attachments", [])
            ],
            "time_logs": [
                {
                    "id": str(log.get("id", ObjectId())),
                    "hours": log["hours"],
                    "description": log.get("description"),
                    "logged_by": str(log["logged_by"]),
                    "logged_at": log["logged_at"]
                }
                for log in task.get("time_logs", [])
            ]
        })
    
    return response_data


def format_defect_response(
    defect: Dict[str, Any],
    version_info: Optional[Dict] = None,
    assignee_info: Optional[Dict] = None,
    reporter_info: Optional[Dict] = None,
    verifier_info: Optional[Dict] = None,
    project_info: Optional[Dict] = None,
    versions_list: Optional[List[Dict]] = None,
    include_details: bool = False
) -> Dict[str, Any]:
    """
    格式化缺陷响应数据
    
    Args:
        defect: 缺陷数据
        version_info: 版本信息（可选，向后兼容，用于单个版本）
        assignee_info: 负责人信息（可选）
        reporter_info: 报告人信息（可选）
        verifier_info: 验证人信息（可选）
        project_info: 项目信息（可选）
        versions_list: 版本列表（可选，用于多个版本）
        include_details: 是否包含详细信息（评论、附件等）
    
    Returns:
        格式化后的缺陷数据
    """
    # 计算统计信息
    comment_count = calculate_comment_count(defect.get("comments", []))
    attachment_count = calculate_attachment_count(defect.get("attachments", []))
    
    # 处理版本信息：优先使用versions_list，如果没有则使用version_info
    versions = []
    if versions_list:
        # 如果提供了版本列表，使用它
        versions = versions_list
    elif version_info is not None:
        # 如果没有版本列表但有单个版本信息，使用它
        versions = [version_info]
    
    # 格式化版本列表
    formatted_versions = []
    for v in versions:
        if v is not None and isinstance(v, dict):  # 确保版本数据不为None且是字典类型
            # 尝试多种可能的字段名来获取版本ID
            version_id = v.get("_id") or v.get("id")
            if version_id:  # 只要有ID就格式化
                formatted_versions.append({
                    "id": str(version_id),
                    "name": v.get("name") or "",  # 确保name不为None
                    "version_number": v.get("version_number") or ""  # 确保version_number不为None
                })
    
    # 确保如果versions_list有值，formatted_versions必须有数据返回
    # 如果versions_list不为空但formatted_versions为空，说明数据格式有问题
    # 这种情况可能是版本数据缺少_id字段，需要确保所有版本数据都有_id
    if versions_list and not formatted_versions:
        # 尝试重新处理，确保所有有效的版本数据都被包含
        for v in versions_list:
            if v is not None and isinstance(v, dict):  # 只要v不为None且是字典类型，就尝试格式化
                version_id = v.get("_id") or v.get("id")  # 尝试多种可能的字段名
                if version_id:
                    formatted_versions.append({
                        "id": str(version_id),
                        "name": v.get("name") or "",
                        "version_number": v.get("version_number") or ""
                    })
    
    # 确保formatted_versions始终是一个列表（即使为空）
    if formatted_versions is None:
        formatted_versions = []
    
    # 基础响应数据
    response_data = {
        "id": str(defect["_id"]),
        "title": defect["title"],
        "description": defect.get("description"),
        "type": defect["type"],
        "status": defect["status"],
        "priority": defect["priority"],
        "severity": defect["severity"],
        "source": defect["source"],
        "project_id": str(defect["project_id"]) if defect.get("project_id") else None,
        "project_name": project_info.get("name") if project_info else None,
        "assignee_id": str(defect["assignee_id"]) if defect.get("assignee_id") else None,
        "assignee_name": assignee_info.get("name") if assignee_info else None,
        "reporter_id": str(defect["reporter_id"]) if defect.get("reporter_id") else None,
        "reporter_name": reporter_info.get("name") if reporter_info else None,
        "verifier_id": str(defect["verifier_id"]) if defect.get("verifier_id") else None,
        "verifier_name": verifier_info.get("name") if verifier_info else None,
        "steps_to_reproduce": defect.get("steps_to_reproduce"),
        "expected_result": defect.get("expected_result"),
        "actual_result": defect.get("actual_result"),
        "environment_info": defect.get("environment_info", {}),
        "found_date": defect.get("found_date").isoformat() if defect.get("found_date") else None,
        "resolved_date": defect.get("resolved_date").isoformat() if defect.get("resolved_date") else None,
        "verified_date": defect.get("verified_date").isoformat() if defect.get("verified_date") else None,
        "completed_at": defect.get("completed_at").isoformat() if defect.get("completed_at") else None,
        "actual_completed_at": defect.get("actual_completed_at").isoformat() if defect.get("actual_completed_at") else None,
        "tags": defect.get("tags", []),
        "organization_id": str(defect["organization_id"]) if defect.get("organization_id") else None,
        "created_by": str(defect["created_by"]) if defect.get("created_by") else None,
        "created_at": defect.get("created_at").isoformat() if defect.get("created_at") else None,
        "updated_at": defect.get("updated_at").isoformat() if defect.get("updated_at") else None,
        "comment_count": comment_count,
        "attachment_count": attachment_count,
        # 版本信息（使用数组格式，支持多版本）
        "versions": formatted_versions
    }
    
    # 如果需要详细信息，添加完整的评论和附件
    if include_details:
        response_data.update({
            "comments": [
                {
                    "id": str(comment.get("id", ObjectId())),
                    "content": comment["content"],
                    "author_id": str(comment["author_id"]),
                    "created_at": comment["created_at"].isoformat() if comment.get("created_at") else None,
                    "updated_at": comment.get("updated_at").isoformat() if comment.get("updated_at") else None
                }
                for comment in defect.get("comments", [])
            ],
            "attachments": [
                {
                    "id": str(attachment.get("id", ObjectId())),
                    "filename": attachment["filename"],
                    "file_path": attachment["file_path"],
                    "file_size": attachment["file_size"],
                    "content_type": attachment["content_type"],
                    "uploaded_by": str(attachment["uploaded_by"]),
                    "uploaded_at": attachment["uploaded_at"].isoformat() if attachment.get("uploaded_at") else None
                }
                for attachment in defect.get("attachments", [])
            ]
        })
    
    return response_data


def format_requirement_response(
    requirement: Dict[str, Any],
    project_name: Optional[str] = None,
    assignee_name: Optional[str] = None,
    reporter_name: Optional[str] = None,
    include_details: bool = False
) -> Dict[str, Any]:
    """
    格式化需求响应数据
    
    Args:
        requirement: 需求数据
        project_name: 项目名称
        assignee_name: 指派人姓名
        reporter_name: 报告人姓名
        include_details: 是否包含详细信息
    
    Returns:
        格式化后的需求数据
    """
    # 计算进度和逾期状态
    progress = calculate_requirement_progress(requirement["status"])
    is_overdue = is_requirement_overdue(requirement.get("due_date"), requirement["status"])
    
    # 基础响应数据
    response_data = {
        "id": str(requirement["_id"]),
        "title": requirement["title"],
        "description": requirement.get("description"),
        "requirement_type": requirement["requirement_type"],
        "status": requirement["status"],
        "priority": requirement["priority"],
        "source": requirement["source"],
        "project_id": str(requirement["project_id"]),
        "project_name": project_name,
        "assignee_id": str(requirement["assignee_id"]) if requirement.get("assignee_id") else None,
        "assignee_name": assignee_name,
        "reporter_id": str(requirement["reporter_id"]),
        "reporter_name": reporter_name,
        "acceptance_criteria": requirement.get("acceptance_criteria"),
        "business_value": requirement.get("business_value"),
        "estimated_effort": requirement.get("estimated_effort"),
        "actual_effort": requirement.get("actual_effort"),
        "start_date": requirement.get("start_date"),
        "due_date": requirement.get("due_date"),
        "tags": requirement.get("tags", []),
        "dependencies": requirement.get("dependencies", []),
        "watchers": [str(wid) for wid in requirement.get("watchers", [])],
        "created_at": requirement["created_at"],
        "updated_at": requirement["updated_at"],
        "approved_at": requirement.get("approved_at"),
        "implemented_at": requirement.get("implemented_at"),
        "is_overdue": is_overdue,
        "progress": progress,
        "related_tasks_count": 0  # TODO: 实现关联任务统计
    }
    
    # 如果需要详细信息，添加评论和附件
    if include_details:
        response_data.update({
            "comments": requirement.get("comments", []),
            "attachments": requirement.get("attachments", [])
        })
    
    return response_data


def calculate_project_progress(
    requirement_count: int = 0,
    completed_requirement_count: int = 0,
    task_count: int = 0,
    completed_task_count: int = 0,
    defect_count: int = 0,
    resolved_defect_count: int = 0,
    test_case_count: int = 0,
    passed_test_case_count: int = 0,
    project_status: Optional[str] = None,
    start_date: Optional[datetime] = None,
    end_date: Optional[datetime] = None
) -> float:
    """
    综合计算项目进度（多维度加权平均）
    
    计算方案：
    1. 需求完成率（权重：40%）
    2. 任务完成率（权重：35%）
    3. 缺陷解决率（权重：15%）
    4. 测试用例通过率（权重：10%）
    
    如果项目状态是已完成/已归档，直接返回100%
    如果项目状态是已取消，返回0%
    如果没有任何数据，根据项目状态返回默认进度
    """
    # 如果项目状态是已完成/已归档，直接返回100%
    if project_status:
        status_lower = project_status.lower()
        if any(keyword in status_lower for keyword in ["done", "completed", "finished", "已完", "归档"]):
            return 100.0
        # 如果项目状态是已取消，返回0%
        if any(keyword in status_lower for keyword in ["cancelled", "cancel", "已取消", "取消"]):
            return 0.0
    
    # 计算各项完成率
    requirement_progress = 0.0
    if requirement_count > 0:
        requirement_progress = (completed_requirement_count / requirement_count) * 100
    elif requirement_count == 0 and task_count == 0 and defect_count == 0 and test_case_count == 0:
        # 如果没有任何数据，根据项目状态返回默认进度
        if project_status:
            status_lower = project_status.lower()
            if any(keyword in status_lower for keyword in ["planning", "规划", "草稿", "draft"]):
                return 5.0
            elif any(keyword in status_lower for keyword in ["in_progress", "进行", "开发", "开发中"]):
                return 30.0
            elif any(keyword in status_lower for keyword in ["testing", "测试", "测试中"]):
                return 70.0
            elif any(keyword in status_lower for keyword in ["review", "评审", "预发布"]):
                return 90.0
        return 0.0
    
    task_progress = 0.0
    if task_count > 0:
        task_progress = (completed_task_count / task_count) * 100
    
    defect_progress = 0.0
    if defect_count > 0:
        defect_progress = (resolved_defect_count / defect_count) * 100
    elif defect_count == 0:
        # 如果没有缺陷，缺陷进度按100%计算（不影响整体进度）
        defect_progress = 100.0
    
    test_case_progress = 0.0
    if test_case_count > 0:
        test_case_progress = (passed_test_case_count / test_case_count) * 100
    elif test_case_count == 0:
        # 如果没有测试用例，测试用例进度按100%计算（不影响整体进度）
        test_case_progress = 100.0
    
    # 计算加权平均
    total_weight = 0.0
    weighted_sum = 0.0
    
    # 需求权重：40%
    if requirement_count > 0:
        weighted_sum += requirement_progress * 0.4
        total_weight += 0.4
    
    # 任务权重：35%
    if task_count > 0:
        weighted_sum += task_progress * 0.35
        total_weight += 0.35
    
    # 缺陷权重：15%（如果有缺陷数据）
    if defect_count > 0:
        weighted_sum += defect_progress * 0.15
        total_weight += 0.15
    
    # 测试用例权重：10%（如果有测试用例数据）
    if test_case_count > 0:
        weighted_sum += test_case_progress * 0.1
        total_weight += 0.1
    
    # 如果没有任何有效数据，返回0
    if total_weight == 0:
        return 0.0
    
    # 计算加权平均进度
    progress = weighted_sum / total_weight
    
    # 考虑时间进度作为上限参考（可选）
    if start_date and end_date:
        try:
            now = datetime.utcnow()
            if now >= start_date:
                total_duration = (end_date - start_date).total_seconds()
                elapsed_duration = (now - start_date).total_seconds()
                if total_duration > 0:
                    time_progress = (elapsed_duration / total_duration) * 100
                    # 如果时间进度已经超过100%，且实际进度也接近完成，返回100%
                    if time_progress >= 100 and progress >= 90:
                        return 100.0
                    # 如果实际进度远超时间进度（超过20%），适当调整
                    # 但不超过时间进度+20%
                    if progress > time_progress + 20:
                        progress = min(progress, time_progress + 20)
        except Exception:
            # 如果日期计算出错，忽略时间因素
            pass
    
    # 确保进度在0-100之间
    return max(0.0, min(100.0, round(progress, 2)))